home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
smaltalk.lha
/
smalltalk-1.1.1
/
mstsave.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-12
|
21KB
|
893 lines
/***********************************************************************
*
* Binary image save/restore.
*
***********************************************************************/
/***********************************************************************
*
* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
* Written by Steve Byrne.
*
* This file is part of GNU Smalltalk.
*
* GNU Smalltalk is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 1, or (at your option) any later
* version.
*
* GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* GNU Smalltalk; see the file COPYING. If not, write to the Free Software
* Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
***********************************************************************/
/*
* Change Log
* ============================================================================
* Author Date Change
* sbyrne 17 Apr 90 Fixing binary save to save only to the maximum used
* OOP slot, instead of saving the entire OOP table.
* This should improve load time and decrease disk
* storage requirements.
*
* sbyrne 11 Feb 90 Changed the header to record the size of the oop
* table, since trying to load back into a system with a
* different sized oop table loses bigtime.
*
* sbyrne 5 Apr 89 modified to reflect change in classes: now their name
* is a Smalltalk string; before, it was a C string that
* had to be saved specially.
*
* sbyrne 4 Mar 89 Created.
*
*/
#include <stdio.h>
#include "mst.h"
#include "mstsave.h"
#include "mstcomp.h"
#include "mstinterp.h"
#include "mstdict.h"
#include "mstsym.h"
#include "mstoop.h" /* indirectly defines oopAt for sym tab prof */
#include "mstmain.h"
#ifdef HAS_ALLOCA_H
#include <alloca.h>
#endif
#include <stdio.h>
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024 /* max length of a file and path */
#endif
#define fromBeginning 0 /* symbolic name for file offset modifier */
/* convert to a relative offset from start of OOP table */
#define toRelative(obj) \
( (OOP)((long)(obj) - (long)oopTable) )
/* convert from relative offset to actual oop table address */
#define fromRelative(obj) \
( (OOP)((long)(obj) + (long)oopTable) )
/* round "x" up to the next 4 byte boundary */
#define roundUpWord(x) \
( ((x) + 3) & ~3 )
/*
* The binary image file has the following format:
*
* header
* complete oop table
* global oop variable data
* objects and non-oop object data
* char object data
* nil object
* boolean objects
*/
typedef struct SaveFileHeaderStruct {
long version; /* the Smalltalk version that made this dump */
long objectDataSize; /* size of object data section in bytes */
long oopTableSize; /* size of the oop table at dump */
} SaveFileHeader;
typedef struct OOPVectorStruct {
Object base; /* base of the storage */
Object ptr; /* the current object */
} OOPVector;
OOP *globalOOPs[] = {
&andColonSymbol,
&atColonPutColonSymbol,
&atColonSymbol,
&atEndSymbol,
&bitAndColonSymbol,
&bitOrColonSymbol,
&bitShiftColonSymbol,
&blockCopyColonSymbol,
&classSymbol,
÷Symbol,
&doColonSymbol,
&equalSymbol,
&greaterEqualSymbol,
&greaterThanSymbol,
&ifFalseColonIfTrueColonSymbol,
&ifFalseColonSymbol,
&ifTrueColonIfFalseColonSymbol,
&ifTrueColonSymbol,
&integerDivideSymbol,
&lessEqualSymbol,
&lessThanSymbol,
&minusSymbol,
&newColonSymbol,
&newSymbol,
&nextPutColonSymbol,
&nextSymbol,
¬EqualSymbol,
¬SameObjectSymbol,
&orColonSymbol,
&plusSymbol,
&remainderSymbol,
&sameObjectSymbol,
&sizeSymbol,
&thisContextSymbol,
×Symbol,
&valueColonSymbol,
&valueColonValueColonSymbol,
&valueColonValueColonValueColonSymbol,
&valueWithArgumentsColonSymbol,
&valueSymbol,
&whileFalseColonSymbol,
&whileTrueColonSymbol,
&orSymbol,
&andSymbol,
&superSymbol,
&nilSymbol,
&trueSymbol,
&falseSymbol,
&selfSymbol,
&doesNotUnderstandColonSymbol,
&unknownSymbol,
&charSymbol,
&stringSymbol,
&stringOutSymbol,
&symbolSymbol,
&intSymbol,
&longSymbol,
&doubleSymbol,
&voidSymbol,
&variadicSymbol,
&cObjectSymbol,
&smalltalkSymbol,
&byteArraySymbol,
&objectClass,
&magnitudeClass,
&charClass,
&timeClass,
&numberClass,
&floatClass,
&integerClass,
&lookupKeyClass,
&associationClass,
&linkClass,
&processClass,
&symLinkClass,
&collectionClass,
&sequenceableCollectionClass,
&linkedListClass,
&semaphoreClass,
&arrayedCollectionClass,
&arrayClass,
&stringClass,
&symbolClass,
&byteArrayClass,
&compiledMethodClass,
&intervalClass,
&orderedCollectionClass,
&sortedCollectionClass,
&bagClass,
&mappedCollectionClass,
&setClass,
&dictionaryClass,
&identityDictionaryClass,
&systemDictionaryClass,
&undefinedObjectClass,
&booleanClass,
&falseClass,
&trueClass,
&processorSchedulerClass,
&delayClass,
&sharedQueueClass,
&behaviorClass,
&classDescriptionClass,
&classClass,
&metaclassClass,
&smalltalkDictionary,
&messageClass,
&methodContextClass,
&blockContextClass,
&streamClass,
&positionableStreamClass,
&readStreamClass,
&writeStreamClass,
&readWriteStreamClass,
&cObjectClass,
&fileStreamClass,
&memoryClass,
&byteMemoryClass,
&wordMemoryClass,
&randomClass,
&cFuncDescriptorClass,
&tokenStreamClass,
&methodInfoClass,
&fileSegmentClass,
&nilOOP,
&trueOOP,
&falseOOP,
&processorOOP,
&symbolTable,
nil
};
static void skipOverHeader(), saveObject(), fixupObject(),
fixupMethodObject(), restoreObject(), restoreMethodObject(),
saveOOPTable(), fixupAllOOPs(), fixupOOP(),
/* fixupFreeOOP(), */restoreAllOOPs(), restoreOOP(),
/*restoreFreeOOP(), */loadOOPTable(), loadNormalOOPs(),
loadCharOOPs(), loadSpecialOOPs(), saveGlobalOOPs(),
loadGlobalOOPs(), fixupClassObject(), restoreInstanceVars(),
restoreClassObject(), saveFileVersion(),
loadFileVersion(), fixupInstanceVars(), fixupOOPInstanceVars();
static int saveNormalOOPs(), saveAllObjects();
/* This variable contains the OOP slot index of the highest non-free OOP,
* excluding the built-in ones (i.e., it will always be < OOP_TABLE_SIZE).
* This is used for optimizing the size of the saved image, and minimizing
* the load time when restoring the system. */
static int maxUsedOOPSlot = 0;
Boolean saveToFile(fileName)
char *fileName;
{
FILE *imageFile;
long objectDataSize;
Boolean oldGCState;
fullGC(); /* make sure that the world is compact if
possible */
oldGCState = gcOff();
#ifdef BINARY_MODE_NEEDED
imageFile = fopen(fileName, "wb");
#else
imageFile = fopen(fileName, "w");
#endif
if (imageFile == NULL) {
errorf("Couldn't open file %s", fileName);
return (false);
}
skipOverHeader(imageFile);
saveOOPTable(imageFile);
#ifdef OOP_TABLE_TRACE
printf("After saving oopt table: %d\n", ftell(imageFile));
#endif /* OOP_TABLE_TRACE */
saveGlobalOOPs(imageFile);
#ifdef OOP_TABLE_TRACE
printf("After global oop table: %d\n", ftell(imageFile));
#endif /* OOP_TABLE_TRACE */
objectDataSize = saveAllObjects(imageFile);
#ifdef OOP_TABLE_TRACE
printf("After saving all objects table: %d\n", ftell(imageFile));
#endif /* OOP_TABLE_TRACE */
skipToHeader(imageFile);
saveFileVersion(imageFile, objectDataSize);
fclose(imageFile);
setGCState(oldGCState);
return (true);
}
static void skipOverHeader(imageFile)
FILE *imageFile;
{
unsigned long pos;
fseek(imageFile, sizeof(SaveFileHeader), fromBeginning);
}
/*
* static void saveOOPTable(imageFile)
*
* Description
*
* Writes the OOP table out to the image file. We need to make all
* of the object pointers relative, including free OOP table slots, and
* we use a parallel vector containing file offsets for the objects that
* we developed during saving of the objects themselves as the fixup
* table.
*
* Inputs
*
* imageFile:
* A stdio FILE to be written to. It must be positioned
* correctly before this routine is called.
*
*/
static void saveOOPTable(imageFile)
FILE *imageFile;
{
fixupAllOOPs();
#ifdef OOP_TABLE_TRACE
printf("there are %d free oops out of %d oops, leaving %d\n",
numFreeOOPs, OOP_TABLE_SIZE, OOP_TABLE_SIZE - numFreeOOPs);
printf("max used is %d\n", maxUsedOOPSlot);
#endif /* OOP_TABLE_TRACE */
/* save up to the max oop slot in use */
fwrite(oopTable, sizeof(struct OOPStruct), maxUsedOOPSlot + 1, imageFile);
/* then save the constant ones at the end */
fwrite(&oopTable[OOP_TABLE_SIZE], sizeof(struct OOPStruct),
TOTAL_OOP_TABLE_SLOTS - OOP_TABLE_SIZE, imageFile);
restoreAllOOPs();
}
static void fixupAllOOPs()
{
int i;
maxUsedOOPSlot = 0;
for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
fixupOOP(i);
}
}
static void fixupOOP(i)
int i;
{
OOP oop;
oop = oopAt(i);
#ifdef old_code /* Tue Apr 17 22:48:45 1990 */
/**/ if (oop->isFree) {
/**/ fixupFreeOOP(oop);
/**/ } else {
#endif /* old_code Tue Apr 17 22:48:45 1990 */
if (!oop->isFree) {
if (i < OOP_TABLE_SIZE) {
maxUsedOOPSlot = i;
}
oop->object = (Object)toRelative(oop->object);
}
}
#ifdef old_code /* Tue Apr 17 22:49:42 1990 */
/**/
/**/static void fixupFreeOOP(oop)
/**/OOP oop;
/**/{
/**/ if (oop->object == nil) {
/**/ oop->object = (Object)-1L;
/**/ } else {
/**/ oop->object = (Object)toRelative(oop->object);
/**/ }
/**/
/**/ oop->isFree = 0;
/**/ if (oop->prevFree == (long)nil) {
/**/ oop->prevFree = -1L;
/**/ } else {
/**/ oop->prevFree = (long)toRelative(oop->prevFree);
/**/ }
/**/
/**/ oop->isFree = 1;
/**/}
#endif /* old_code Tue Apr 17 22:49:42 1990 */
static void restoreAllOOPs()
{
int i;
for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
restoreOOP(i);
}
}
static void restoreOOP(i)
int i;
{
OOP oop;
oop = oopAt(i);
#ifdef old_code /* Tue Apr 17 22:50:19 1990 */
/**/ if (oop->isFree) {
/**/ restoreFreeOOP(oop);
/**/ } else {
#endif /* old_code Tue Apr 17 22:50:19 1990 */
if (!oop->isFree) {
oop->object = (Object)fromRelative(oop->object);
}
}
#ifdef old_code /* Tue Apr 17 22:50:39 1990 */
/**/static void restoreFreeOOP(oop)
/**/OOP oop;
/**/{
/**/ if (oop->object == (Object)-1L) {
/**/ oop->object = nil;
/**/ } else {
/**/ oop->object = (Object)fromRelative(oop->object);
/**/ }
/**/
/**/ if (oop->prevFree == -1L) {
/**/ oop->prevFree = (long)nil;
/**/ } else {
/**/ oop->isFree = 0;
/**/ oop->prevFree = (long)fromRelative(oop->prevFree);
/**/ }
/**/
/**/ oop->isFree = 1;
/**/}
#endif /* old_code Tue Apr 17 22:50:39 1990 */
static void saveGlobalOOPs(imageFile)
FILE *imageFile;
{
OOP **oopPtr, oop;
for (oopPtr = globalOOPs; *oopPtr; oopPtr++) {
oop = toRelative(**oopPtr);
fwrite(&oop, sizeof(OOP), 1, imageFile);
}
}
static int saveAllObjects(imageFile)
FILE *imageFile;
{
long objectStart, objectEnd;
int i;
OOP oop;
objectStart = ftell(imageFile);
for (i = 0; i < OOP_TABLE_SIZE; i++) {
oop = oopAt(i);
if (oopValid(oop)) {
saveObject(imageFile, oop);
}
}
objectEnd = ftell(imageFile);
/* dump out the character objects, nil, true, and false */
for (i = OOP_TABLE_SIZE; i < TOTAL_OOP_TABLE_SLOTS; i++) {
saveObject(imageFile, oopAt(i));
}
return (objectEnd - objectStart);
}
static void saveObject(imageFile, oop)
FILE *imageFile;
OOP oop;
{
Object object;
int numFixed, numIndexed;
Boolean hasPointers;
object = oopToObj(oop);
hasPointers = isPointers(oop);
numFixed = oopFixedFields(oop);
numIndexed = numIndexableFields(oop);
fixupObject(oop, hasPointers, numFixed, numIndexed);
fwrite(object, sizeof(OOP), object->objSize, imageFile);
restoreObject(oop, hasPointers, numFixed, numIndexed);
}
static void fixupObject(oop, hasPointers, numFixed, numIndexed)
OOP oop;
Boolean hasPointers;
int numFixed, numIndexed;
{
int i;
Object object;
OOP instOOP, classOOP;
classOOP = oopClass(oop);
if (classOOP == compiledMethodClass) {
fixupMethodObject(oop);
} else {
if (hasPointers) {
for (i = 1; i <= numFixed + numIndexed; i++) {
instOOP = instVarAt(oop, i);
if (!isInt(instOOP)) {
instVarAtPut(oop, i, toRelative(instOOP));
}
}
}
}
object = oopToObj(oop);
object->objClass = toRelative(object->objClass);
}
static void fixupMethodObject(oop)
OOP oop;
{
MethodHeader header;
int i;
OOP literalOOP, descriptorOOP;
descriptorOOP = getMethodDescriptor(oop);
if (!isInt(descriptorOOP)) {
setMethodDescriptor(oop, toRelative(descriptorOOP));
}
header = getMethodHeaderExt(oop);
if (header.headerFlag == 1 || header.headerFlag == 2) {
/* these have no method literals to fix up, so we ignore them */
return;
}
for (i = 0; i < header.numLiterals; i++) {
literalOOP = methodLiteralExt(oop, i);
if (!isInt(literalOOP)) {
storeMethodLiteralNoGC(oop, i, toRelative(literalOOP));
}
}
}
static void restoreObject(oop, hasPointers, numFixed, numIndexed)
OOP oop;
Boolean hasPointers;
int numFixed, numIndexed;
{
Object object;
object = oopToObj(oop);
object->objClass = fromRelative(object->objClass);
restoreInstanceVars(oop, hasPointers, numFixed, numIndexed);
}
static void restoreInstanceVars(oop, hasPointers, numFixed, numIndexed)
OOP oop;
Boolean hasPointers;
int numFixed, numIndexed;
{
register int i;
OOP instOOP, classOOP;
classOOP = oopClass(oop);
if (classOOP == compiledMethodClass) {
restoreMethodObject(oop);
} else {
if (hasPointers) {
for (i = 1; i <= numFixed + numIndexed; i++) {
instOOP = instVarAt(oop, i);
if (!isInt(instOOP)) {
instVarAtPut(oop, i, fromRelative(instOOP));
}
}
if (classOOP == cFuncDescriptorClass) {
restoreCFuncDescriptor(oop); /* in mstcint.c */
}
}
}
}
static void restoreMethodObject(oop)
OOP oop;
{
MethodHeader header;
int i;
OOP literalOOP, descriptorOOP;
descriptorOOP = getMethodDescriptor(oop);
if (!isInt(descriptorOOP)) {
setMethodDescriptor(oop, fromRelative(descriptorOOP));
}
header = getMethodHeaderExt(oop);
if (header.headerFlag == 1 || header.headerFlag == 2) {
/* these have no method literals to fix up, so we ignore them */
return;
}
for (i = 0; i < header.numLiterals; i++) {
literalOOP = methodLiteralExt(oop, i);
if (!isInt(literalOOP)) {
storeMethodLiteralNoGC(oop, i, fromRelative(literalOOP));
}
}
}
skipToHeader(imageFile)
FILE *imageFile;
{
rewind(imageFile);
}
static void saveFileVersion(imageFile, objectDataSize)
FILE *imageFile;
long objectDataSize;
{
SaveFileHeader header;
header.version = sysVersMajor * 1000000 + sysVersMinor * 1000 + sysVersEdit;
header.objectDataSize = objectDataSize;
header.oopTableSize = maxUsedOOPSlot + 1; /* n slots, numbered 0..n-1 */
fwrite(&header, sizeof(SaveFileHeader), 1, imageFile);
}
static void skipToOOPTable(imageFile)
FILE *imageFile;
{
rewind(imageFile);
}
/***********************************************************************
*
* Binary loading routines.
*
***********************************************************************/
Boolean loadFromFile(fileName)
char *fileName;
{
FILE *imageFile;
SaveFileHeader header;
OOPVector ov;
Boolean oldGCState;
char fullImageName[MAXPATHLEN];
oldGCState = gcOff();
findImageFile(fileName, fullImageName);
#ifdef BINARY_MODE_NEEDED
imageFile = fopen(fullImageName, "rb");
#else
imageFile = fopen(fullImageName, "r");
#endif
if (imageFile == NULL) {
return (false);
}
loadFileVersion(imageFile, &header);
if (header.version != (sysVersMajor * 1000000 + sysVersMinor * 1000
+ sysVersEdit)) {
/* version mismatch; this image file is invalid */
return (false);
}
#ifdef old_code /* Tue Apr 17 22:25:33 1990 */
/**/ if (header.oopTableSize != OOP_TABLE_SIZE) {
/**/ return (false);
/**/ }
#endif /* old_code Tue Apr 17 22:25:33 1990 */
loadOOPTable(imageFile, header.oopTableSize);
loadGlobalOOPs(imageFile);
loadNormalOOPs(imageFile, header.objectDataSize, &ov);
loadCharOOPs(imageFile);
loadSpecialOOPs(imageFile);
fixupInstanceVars(&ov);
fclose(imageFile);
setGCState(oldGCState);
return (true);
}
static void loadFileVersion(imageFile, headerp)
FILE *imageFile;
SaveFileHeader *headerp;
{
fread(headerp, sizeof(SaveFileHeader), 1, imageFile);
}
static void loadOOPTable(imageFile, oldSlotsUsed)
FILE *imageFile;
long oldSlotsUsed;
{
long i;
OOP oop;
/* fread(oopTable, sizeof(struct OOPStruct), TOTAL_OOP_TABLE_SLOTS, imageFile);*/
/* load in the valid OOP slots from previous dump */
fread(oopTable, sizeof(struct OOPStruct), oldSlotsUsed, imageFile);
/* mark the remaining ones as available */
for (i = oldSlotsUsed; i < OOP_TABLE_SIZE; i++) {
oop = oopAt(i);
oop->isFree = true;
}
/* read in the constant stuff at the end */
fread(&oopTable[OOP_TABLE_SIZE], sizeof(struct OOPStruct),
TOTAL_OOP_TABLE_SLOTS - OOP_TABLE_SIZE, imageFile);
/* the fixup gets handled by load normal oops */
}
static void loadGlobalOOPs(imageFile)
FILE *imageFile;
{
OOP **oopPtr, oop, *oopVec;
long numGlobalOOPs;
for (numGlobalOOPs = 0, oopPtr = globalOOPs; *oopPtr;
oopPtr++, numGlobalOOPs++);
oopVec = (OOP *)alloca(numGlobalOOPs * sizeof(OOP));
fread(oopVec, sizeof(OOP), numGlobalOOPs, imageFile);
for (oopPtr = globalOOPs; *oopPtr; oopPtr++, oopVec++) {
**oopPtr = fromRelative(*oopVec);
}
#ifdef old_code /* Wed Apr 26 21:15:38 1989 */ /* <<<== what dedication...3 days before my wedding -- SBB */
/**/ /* ??? this could be sped up by using alloca, doing one fread, and then
/**/ iterating through the array */
/**/ for (oopPtr = globalOOPs; *oopPtr; oopPtr++) {
/**/ fread(&oop, sizeof(OOP), 1, imageFile);
/**/ **oopPtr = fromRelative(oop);
/**/ }
#endif /* old_code Wed Apr 26 21:15:38 1989 */
}
static void loadNormalOOPs(imageFile, objectDataSize, ovp)
FILE *imageFile;
long objectDataSize;
OOPVector *ovp;
{
register long i;
OOP oop, prevFreeOOP;
Object object, objPtr;
objPtr = curSpaceAddr();
ovp->base = objPtr;
prevFreeOOP = nil;
fread(objPtr, 1, objectDataSize, imageFile);
freeOOPs = nil;
numFreeOOPs = 0;
for (i = 0; i < OOP_TABLE_SIZE; i++) {
oop = oopAt(i);
if (oopValid(oop)) {
object = objPtr;
oop->object = object;
/* ### should probably make this setting symbolic/abstracted */
oop->inSpace = toSpace;
oop->oddMark = toSpace;
oop->evenMark = !toSpace;
object->objClass = fromRelative(object->objClass);
objPtr = (Object)((long *)object + object->objSize);
} else if (oop->isFree) { /* ignore non-free but non-valid...they'll get handled
naturally in due time. */
numFreeOOPs++;
if (prevFreeOOP) { /* forward chain the oop free list */
prevFreeOOP->object = (Object)oop;
}
if (freeOOPs == nil) { /* free list points at first free oop in
OOP table */
freeOOPs = oop;
}
prevFreeOOP = oop;
}
}
if (prevFreeOOP) {
prevFreeOOP->object = nil; /* terminate the free list nicely */
}
setSpaceInfo(objectDataSize);
ovp->ptr = objPtr;
}
static void loadCharOOPs(imageFile)
FILE *imageFile;
{
int i;
fread(charObjectTable, sizeof(CharObject), NUM_CHAR_OBJECTS, imageFile);
for (i = 0; i < NUM_CHAR_OBJECTS; i++) {
oopTable[i + CHAR_OBJECT_BASE].object = (Object)&charObjectTable[i];
oopTable[i + CHAR_OBJECT_BASE].inSpace = toSpace;
charObjectTable[i].objClass = fromRelative(charObjectTable[i].objClass);
}
}
static void loadSpecialOOPs(imageFile)
FILE *imageFile;
{
fread(&nilObject, sizeof(struct NilObjectStruct), 1, imageFile);
nilOOP->object = (Object)&nilObject;
nilOOP->object->objClass = fromRelative(nilOOP->object->objClass);
nilOOP->inSpace = toSpace;
fread(booleanObjects, sizeof(struct BooleanObjectStruct), 2, imageFile);
trueOOP->object = (Object)&booleanObjects[0];
falseOOP->object = (Object)&booleanObjects[1];
trueOOP->object->objClass = fromRelative(trueOOP->object->objClass);
falseOOP->object->objClass = fromRelative(falseOOP->object->objClass);
trueOOP->inSpace = falseOOP->inSpace = toSpace;
}
static void fixupInstanceVars(ovp)
OOPVector *ovp;
{
int i;
OOP oop;
for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
oop = oopAt(i);
if (oopValid(oop)) {
fixupOOPInstanceVars(oop, ovp);
}
}
}
static void fixupOOPInstanceVars(oop, ovp)
OOP oop;
OOPVector *ovp;
{
int numFixed, numIndexed;
Boolean hasPointers;
hasPointers = isPointers(oop);
numFixed = oopFixedFields(oop);
numIndexed = numIndexableFields(oop);
restoreInstanceVars(oop, hasPointers, numFixed, numIndexed);
}